package edu.tsinghua.ddb.components;

import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import edu.tsinghua.ddb.beans.QueryTree;
import edu.tsinghua.ddb.beans.queryTreeNode.MultiChildNode;
import edu.tsinghua.ddb.beans.queryTreeNode.QJoin;
import edu.tsinghua.ddb.beans.queryTreeNode.QLeaf;
import edu.tsinghua.ddb.beans.queryTreeNode.QProject;
import edu.tsinghua.ddb.beans.queryTreeNode.QSelect;
import edu.tsinghua.ddb.main.console.MyLog;

public class BottomProjectOpt extends Optimizelet {

	@Override
	public QueryTree opt(QueryTree qt) throws SQLException {
		/*
		 * each leaf should project on such fileds: those appear in the
		 * selectlet targets; those appear in the Qjoin on the path to the query
		 * tree root.
		 */
		assert qt instanceof QProject;
		QProject root = (QProject) qt;
		List<String> fields0 = root.getTargets();

		List<String> fieldsOnPath = new LinkedList<String>(fields0);
		// wash1(fieldsOnPath, root);
		// MyLog.debug(fieldsOnPath);
		// wash2(fieldsOnPath, root);
		projectDownward(fieldsOnPath, root.getSubNode());

		return root;
	}

	private void projectDownward(List<String> fieldsOnPath, QueryTree qt) {
		if (qt instanceof QProject) {
			projectDownward(fieldsOnPath, ((QProject) qt).getSubNode());
		} else if (qt instanceof QSelect) {
			QSelect qselect=(QSelect) qt;
			List<String> fieldsOnPath1 = new LinkedList<String>(
					fieldsOnPath);
			
			fieldsOnPath1.addAll(qselect.getColsNamesInvolved());
			projectDownward(fieldsOnPath1, qselect.getSubNode());
		} else if (qt instanceof QLeaf) {
//			MyLog.debug(fieldsOnPath+">>"+qt);
			((QLeaf) qt).projectOnto(fieldsOnPath);
		} else {
			assert qt instanceof MultiChildNode;
			for (QueryTree q : ((MultiChildNode) qt).getSubNodes()) {
				List<String> fieldsOnPath1 = new LinkedList<String>(
						fieldsOnPath);
				if (qt instanceof QJoin) {
					QJoin qj = (QJoin) qt;
					if (!fieldsOnPath1.contains(qj.getJoinFieldName()[0]))
						fieldsOnPath1.add(qj.getJoinFieldName()[0]);
					if (!fieldsOnPath1.contains(qj.getJoinFieldName()[1]))
						fieldsOnPath1.add(qj.getJoinFieldName()[1]);
				}
				projectDownward(fieldsOnPath1, q);
			}
		}
	}

}
